using System;
using System.Text;
using System.Collections.Generic;
using InfoJetSoft.Service.XPath;

//CID 0164 //2008.12.13 //Begin
namespace InfoJetSoft.Service.XPath.Exprs
{
	/// <summary>
	/// Summary description for MultiplicativeExpr.
	/// </summary>
    public class MultiplicativeExpr : IExpr
	{
        private List<IExpr> unaryList = null;

		public MultiplicativeExpr()
		{
			//
			// TODO: Add constructor logic here
			//
        }

        public object Evaluate(ExprContext context)
        {
            //CID 0804 //2011.02.26 //Begin
            object leftValue = null;
            for (int i = 0; i < this.unaryList.Count; i++)
            {
                IExpr expr = this.unaryList[i];
                if (expr is OperatorExpr)
                {
                    OperatorExpr oper = (OperatorExpr)expr;
                    i++;
                    IExpr nextExpr = this.unaryList[i];
                    object rightValue = nextExpr.Evaluate(context);
                    if (oper.Operator == Operator.Mul)
                    {
                        leftValue = this.Mul(context, leftValue, rightValue);
                    }
                    else if (oper.Operator == Operator.Div)
                    {
                        leftValue = this.Div(context, leftValue, rightValue);
                    }
                    else if (oper.Operator == Operator.Mod)
                    {
                        leftValue = this.Mod(context, leftValue, rightValue);
                    }
                    else
                    {
                        throw new Exception("Unsupported operator: " + oper.Operator);
                    }
                }
                else
                {
                    if (leftValue == null)
                    {
                        leftValue = expr.Evaluate(context);
                    }
                    else
                    {
                        throw new Exception("Unsupported expr order");
                    }
                }
            }
            return leftValue;
            //CID 0804 //2011.02.26 //End
        }

        //CID 0866 //2011.04.01 //Begin
        public void Visit(IExprVisitor visitor)
        {
            for (int i = 0; i < this.unaryList.Count; i++)
            {
                IExpr expr = this.unaryList[i];
                expr.Visit(visitor);
            }
        }
        //CID 0866 //2011.04.01 //End

        //CID 0804 //2011.02.26 //Begin
        private object Mul(ExprContext context, object value1, object value2)
        {
            double number1 = NumberFunctions.number(context, value1);
            double number2 = NumberFunctions.number(context, value2);
            if (double.IsNaN(number1) || double.IsNaN(number2))
            {
                return double.NaN;
            }
            else
            {
                return number1 * number2;
            }
        }
        //CID 0804 //2011.02.26 //End

        //CID 0804 //2011.02.26 //Begin
        private object Div(ExprContext context, object value1, object value2)
        {
            double number1 = NumberFunctions.number(context, value1);
            double number2 = NumberFunctions.number(context, value2);
            if (double.IsNaN(number1) || double.IsNaN(number2))
            {
                return double.NaN;
            }
            else
            {
                return number1 / number2;
            }
        }
        //CID 0804 //2011.02.26 //End

        //CID 0804 //2011.02.26 //Begin
        private object Mod(ExprContext context, object value1, object value2)
        {
            double number1 = NumberFunctions.number(context, value1);
            double number2 = NumberFunctions.number(context, value2);
            if (double.IsNaN(number1) || double.IsNaN(number2))
            {
                return double.NaN;
            }
            else
            {
                return number1 % number2;
            }
        }
        //CID 0804 //2011.02.26 //End

        public void Print(StringBuilder buffer)
        {
            foreach (IExpr expr in this.unaryList)
            {
                expr.Print(buffer);
            }
        }

		public static IExpr Parse( ExprParser parser )
		{
            IExpr unaryExpr = UnaryExpr.Parse(parser);
			if( unaryExpr != null )
			{
                List<IExpr> list = new List<IExpr>();
				list.Add( unaryExpr );

                OperatorExpr multiplicativeOperator = OperatorExpr.ParseMultiplicativeOperator(parser);
				while( multiplicativeOperator != null )
				{
					list.Add( multiplicativeOperator );

                    IExpr nextUnaryExpr = UnaryExpr.Parse(parser);
					if( nextUnaryExpr == null )
					{
						throw new Exception( "Cannot parse " + parser.XPath );
					}
					list.Add( nextUnaryExpr );
					
					multiplicativeOperator = OperatorExpr.ParseMultiplicativeOperator( parser );
				}

                if (list.Count > 1)
                {
                    MultiplicativeExpr mulitiplicativeExpr = new MultiplicativeExpr();
                    mulitiplicativeExpr.unaryList = list;
                    return mulitiplicativeExpr;
                }
                else
                {
                    return unaryExpr;
                }
			}
			return null;
		}
	}
}
//CID 0164 //2008.12.13 //End
